/**
 * @Author       : Hejh(3010733382@qq.com)
 * @Version      : V1.0
 * @Date         : 2024-01-18 16:25:50
 * @Description  : 计划任务接口控制器
 */

const { Op } = require('sequelize')
const Mysequelize = require('@/models')
const R = require('@/models/Response')
const { ScheduleTask, Source } = require('@/models/model')
const { ERROR_USER_CODE } = require('@/constants/errorCode')
const { generatId } = require('@/utils/idUtil')
const { listModel, sortModel } = require('@/utils/controllerCommon')
const WpFile = require('@/models/fileModel')

const schedule = require('node-schedule')

const taskArr = {
  async cleanFile(scheduleId) {
    try {
      const files = await WpFile.findAll({
        include: [
          {
            model: Source,
            as: 'source',
            required: true
            // where: { fileId: null }
          }
        ]
      })
      const fileIds = files.map((item) => BigInt(item.id))

      // 删除这些file
      await WpFile.destroy({
        where: {
          id: {
            [Op.notIn]: fileIds
          }
        }
      })
    } catch (e) {
      // 错误日志记录
      // ctx.body = R.error()
      console.log(e)
    }
    updateScheleTaskInfo(scheduleId)
  },
  exportLog(scheduleId) {
    console.log('日志导出', scheduleId)
    updateScheleTaskInfo(scheduleId)
  },
  secrtyUpdate(scheduleId) {
    console.log('密钥更新', scheduleId)
    updateScheleTaskInfo(scheduleId)
  }
}

// 更新计划任务的最后运行时间
const updateScheleTaskInfo = async (scheduleId) => {
  await ScheduleTask.update(
    {
      lastRunTime: Date.now()
    },
    {
      where: {
        id: scheduleId
      }
    }
  )
}

/**
 * 根据type获取任务函数
 */
const getTaskFnByType = (type) => {
  const taskKeys = Object.keys(taskArr)
  if (taskKeys.includes(type)) {
    return taskArr[type]
  } else {
    return function () {}
  }
}

/**
 * 列表查询计划任务接口
 * @param {*} ctx
 * @returns
 */
module.exports.listScheduleTask = async (ctx) => {
  // const { type, isVisible } = ctx.query
  const whereCondition = {}
  // if (type) {
  //   whereCondition.type = +type
  // }
  // if (isVisible) {
  //   whereCondition.isVisible = +isVisible
  // }
  const orderCondition = [['sort']]
  await listModel(ScheduleTask)(ctx, whereCondition, orderCondition)
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 创建计划任务接口
 * @param {*} ctx
 */
module.exports.createScheduleTask = async (ctx) => {
  const { name, desc, type, time, url, isActive } = ctx.request.body
  const nextId = generatId()
  const sort = await ScheduleTask.max('sort')
  const t = await Mysequelize.transaction()
  let createObj = {
    id: nextId,
    name,
    type: 0,
    time,
    isActive,
    url,
    sort: sort + 1,
    system: 0,
    createUser: ctx.user.id,
    updateUser: ctx.user.id
  }
  if (desc) {
    createObj.desc = desc
  }
  try {
    // 到这里可以进行计划任务的添加了,排序字段默认是最大值
    await ScheduleTask.create(createObj, {
      transaction: t
    })
    if (isActive) {
      const taskName = url.slice(((url.lastIndexOf('.') - 1) >>> 0) + 2)
      const job = schedule.scheduleJob(
        nextId,
        time,
        getTaskFnByType(taskName).bind(null, nextId)
      )
      job.invoke()
    }
    await t.commit()
    ctx.body = R.success()
  } catch (error) {
    console.log(error)
    await t.rollback()
    ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_CREATE_ERROR)
  }
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 更新计划任务接口
 * @param {*} ctx
 */
module.exports.updateScheduleTask = async (ctx) => {
  const t = await Mysequelize.transaction()
  const { scheduleTaskId, name, desc, time, type, url, isActive } =
    ctx.request.body

  // 看当前task是否为系统预设，系统预设时：type，url，time不可修改
  const task = await ScheduleTask.findByPk(BigInt(scheduleTaskId))
  const updateObj = {
    name,
    isActive
  }
  if (!+task.system) {
    updateObj.type = 0
    updateObj.time = time
    updateObj.url = url
  }
  if (desc) {
    updateObj.desc = desc
  }
  try {
    // 之前的计划任务需要停止
    // 进行计划任务信息的更新
    await ScheduleTask.update(updateObj, {
      where: {
        id: BigInt(scheduleTaskId)
      },
      transaction: t
    })
    const myJob = schedule.scheduledJobs[scheduleTaskId]
    if (myJob) {
      myJob.cancel()
    }

    // const taskName=getf
    if (isActive) {
      const taskName = url.slice(((url.lastIndexOf('.') - 1) >>> 0) + 2)
      const job = schedule.scheduleJob(
        scheduleTaskId,
        time,
        getTaskFnByType(taskName).bind(null, scheduleTaskId)
      )
      job.invoke()
    }
    await t.commit()
    ctx.body = R.success()
  } catch (e) {
    console.log(e)
    // 失败时重启计划任务
    await t.rollback()
    ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_UPDATE_ERROR)
  }
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 批量删除计划任务接口
 * @param {*} ctx
 */
module.exports.delScheduleTasks = async (ctx) => {
  const t = await Mysequelize.transaction()
  let { scheduleTaskIds } = ctx.request.body
  scheduleTaskIds = scheduleTaskIds.map((item) => BigInt(item))
  try {
    // 对应的计划任务停止
    // 根据ID获取对应的计划任务
    // 创建一个每天的定时任务，并为其命名为 "dailyTask"
    // 删除计划任务
    await ScheduleTask.destroy({
      where: {
        id: {
          [Op.in]: scheduleTaskIds
        }
      },
      transaction: t
    })
    for (let i = 0; i < scheduleTaskIds.length; i++) {
      const myJob = schedule.scheduledJobs[scheduleTaskIds[i]]
      myJob && myJob.cancel()
    }
    await t.commit()
    ctx.body = R.success()
  } catch (error) {
    // 失败时重启计划任务
    await t.rollback()
    ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_DEL_ERROR)
  }
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 计划任务排序接口
 * @param {*} ctx
 */
module.exports.sortScheduleTasks = async (ctx) => {
  // 传递的计划任务ID顺序即为排序顺序，取出这些ID对应的sort，sort从小到大排序后，依次赋值
  await sortModel(
    ScheduleTask,
    ERROR_USER_CODE.SCHEDULE_TASK_SORT_ERROR,
    'scheduleTaskIds'
  )(ctx)
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 计划任务运行接口
 * @param {*} ctx
 */
module.exports.runScheduleTask = async (ctx) => {
  const { scheduleTaskId } = ctx.request.body
  const myJob = schedule.scheduledJobs[scheduleTaskId]
  const scheduleTask = await ScheduleTask.findByPk(BigInt(scheduleTaskId))

  if (!scheduleTask.isActive) {
    ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_IS_CLOSE)
    return
  }
  try {
    if (myJob) {
      myJob.invoke()
    } else {
      const taskName = scheduleTask.url.slice(
        ((scheduleTask.url.lastIndexOf('.') - 1) >>> 0) + 2
      )
      const job = schedule.scheduleJob(
        scheduleTaskId,
        scheduleTask.time,
        getTaskFnByType(taskName).bind(null, scheduleTaskId)
      )
      job.invoke()
    }
    ctx.body = R.success()
  } catch {
    ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_RUN_ERROR)
  }
}
